home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SPACE 2
/
SPACE - Library 2 - Volume 1.iso
/
program
/
124
/
lib
/
lib.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-06-01
|
15KB
|
748 lines
/*
* C library for MJC 2.0 - startup, stdio, TOS, malloc
* - now cr/nl mapping
* - fopen handles binary or text options
* - MAXBUF is now 1024 for speed
* - exec passes on current process' environment
*/
/* max number of args in argv[] */
#define MAXARG 50
/* header file for stdio implementation */
#define MAXBUF 1024
#define MAXIO 8
struct file {
char mode; /* free or open for read/write */
char fd; /* GEMTOS file descriptor */
int idx; /* next slot in buf read/written */
int len; /* length of the buffer */
char buf[MAXBUF]; /* i/o buffer */
};
/* these are the allowed modes */
#define FREE 0
#define RD 1
#define WR 2
#define RDWR 3
#define BINARY 4
/* these should match what's found in stdio.h, except for FILE */
#define FILE struct file
#define EOF (-1)
#define NULL (0L)
#define EOS ((char)0)
/* these are the GEMDOS trap commands */
#define CREATE 0x3C
#define OPEN 0x3D
#define CLOSE 0x3E
#define READ 0x3F
#define WRITE 0x40
#define LSEEK 0x42
#define SETBLK 0x4A
#define EXIT 0x4C
/*
* the c runtime start up routine for ttp processes
*
* assumes a startup sttp.s of
* . _bstk 2048
* . _estk 4
* taa 7 6
* lll 4 0
* sgl _estk
* lag _estk 7
* jsr _cttp
*/
_cttp(tpa) long tpa; {
extern int _argc;
extern char *environ;
extern char *_argv[MAXARG];
extern FILE *stdin, *stdout, *_fopen();
char *b, *w, *in, *out;
int i;
long x, *lp;
if (tpa == NULL) { /* this happened to me once; I don't know why */
_ps("null tpa\n\r");
return 1;
}
/* compute size of program, give memory back to TOS */
lp = tpa;
x = lp[3] + lp[5] + lp[7] + 0x100;
if (trap(1, SETBLK, 0, tpa, x))
exit(-1);
/* parse the command line */
_argc = 1;
_argv[0] = "yc";
environ = (char *) lp[11];
b = tpa + 0x81;
in = out = NULL;
while (*b) {
while (*b && *b <= ' ') b++;
w = b;
while (*b && *b > ' ') b++;
if (*b) *b++ = 0;
if (*w == '<') in = w+1;
else if (*w == '>') out = w+1;
else if (_argc < MAXARG) _argv[_argc++] = w;
}
_argv[_argc] = 0L;
/* init stdio and re-direct if necessary */
_ioinit();
if (in) {
if (_fopen(stdin, in, "r") == NULL)
_cant(in);
}
if (out) {
if (*out != '>') { /* create */
if (_fopen(stdout, out, "w") == NULL)
_cant(out);
}
else { /* append */
if (_fopen(stdout, ++out, "a") == NULL)
_cant(out);
}
}
/* run the program */
i = main(_argc, _argv, environ);
/* close up shop */
if (in) fclose(stdin);
if (out) fclose(stdout);
exit(i);
}
/* initialize standard i/o */
_ioinit() {
int i;
extern FILE *stdin, *stdout, *stderr;
extern FILE _iobuf[1];
for (i = 0; i < MAXIO; i++) {
_iobuf[i].mode = FREE;
_iobuf[i].idx = _iobuf[i].len = 0;
}
stdin = &_iobuf[0]; stdin->fd = 0;
stdout = &_iobuf[1]; stdout->fd = 1;
stderr = &_iobuf[2]; stderr->fd = 1;
stdin->mode = RDWR | BINARY;
stdout->mode = stderr->mode = RDWR;
}
/* trouble redirecting output */
_cant(s) char *s; {
_ps("can't redirect ");
_ps(s);
_ps("\n\r");
exit(1);
}
/* exit the program */
exit(n) { trap(1, EXIT, n); }
/* execute a program: mode=0 -> load and go; mode=3 -> load and return */
exec(file, args, mode) char *file, *args; int mode; {
extern char *environ;
return trap(1, 0x4B, mode, file, args, environ);
}
/* get environment variable */
char *
getenv(name) char *name; {
extern char *environ;
char *p, *q;
for (p = environ; *p; ) {
for (q = name; *p++ == *q++; )
;
if (p[-1] == '=' && q[-1] == 0)
return p;
while (*p++)
;
}
return NULL;
}
/* data for _cttp */
int _argc;
char *_argv[MAXARG];
char *environ;
/* data for standard i/o */
FILE _iobuf[MAXIO], *stdin, *stdout, *stderr;
/* get options from command line */
extern char *strchr();
extern char *optarg;
extern int optind, opterr, optsubind;
getopt(argc, argv, optstr) char *argv[], *optstr; {
char *o, c;
if (++optind == argc) return EOF;
o = argv[optind];
if (*o == '-') {
c = o[++optsubind];
if (c == '-') return EOF;
optstr = strchr(optstr, c);
if (optstr == NULL) {
if (opterr == 0) {
_ps("unknown option: ");
_ps(o);
_ps("\n\r");
}
optsubind = 0;
return '?';
}
if (optstr[1] == ':') {
optarg = (o[optsubind + 1] != (char)0)
? o + optsubind + 1 : argv[++optind];
optsubind = 0;
if (optarg == NULL) {
if (opterr == 0) {
_ps("missing arg: ");
_ps(o);
_ps("\n\r");
}
return '?';
}
}
else if (o[2] != (char)0) {
optind -= 1;
}
return c;
}
return EOF;
}
char *optarg;
int optind, opterr, optsubind;
_ps(s) char *s; { while (*s) trap(1, 2, *s++); }
/*
* stdio routines
*/
/* return file descriptor of a stream */
fileno(s) FILE *s; { return s->fd; }
/* read a stream */
fread(buf, sz, n, s) char *buf; FILE *s; {
int r;
long nn;
nn = (long) n * (long) sz;
if ((r = trap(1, READ, s->fd, nn, buf)) < 0)
r = 0;
else r = r / sz;
return r;
}
/* write on a stream */
fwrite(buf, sz, n, s) char *buf; FILE *s; {
int r;
long nn;
nn = (long) n * (long) sz;
if ((r = trap(1, WRITE, s->fd, nn, buf)) < 0)
r = 0;
else r = r / sz;
return r;
}
/* seek and ye shall find */
fseek(s, offset, mode) FILE *s; long offset; {
lseek(s->fd, offset, mode);
}
/* re-open a stream */
FILE *
freopen(name, mode, fp) char *name, *mode; FILE *fp; {
FILE *fopen();
fclose(fp);
return fopen(name, mode);
}
/* close a stream */
fclose(s) FILE *s; {
if (s != NULL) {
if ((s->mode & RDWR) == WR) fflush(s);
if (s->fd > 5) trap(1, CLOSE, s->fd);
s->mode = FREE;
}
}
/* get a string from a stream */
char *
fgets(b, n, f) char *b; int n; FILE *f; {
int c, i;
c = getc(f);
if (c == EOF) return NULL;
n--;
for (i = 0; i < n && c != EOF; c = getc(f)) {
b[i++] = c;
if (c == '\n') break;
}
b[i] = 0;
return b;
}
/* open a stream */
FILE *
fopen(name, mode) char *name, *mode; {
int i;
FILE *_fopen();
for (i = 0; i < MAXIO && _iobuf[i].mode != FREE; i++)
;
if (i >= MAXIO) return NULL;
return _fopen(&_iobuf[i], name, mode);
}
FILE *
_fopen(s, name, mode) FILE *s; char *name, *mode; {
int m, fd;
if (strcmp(name, "PRT:") == 0) {
fd = 3;
m = RDWR;
}
else if (strcmp(name, "CON:") == 0) {
fd = 0;
m = RDWR;
}
else if (strcmp(name, "AUX:") == 0) {
fd = 2;
m = RDWR;
}
else {
if (*mode == 'w') {
fd = trap(1, CREATE, name, 0);
m = WR;
}
else if (*mode == 'r') {
fd = trap(1, OPEN, name, 0);
m = RD;
}
else if (*mode == 'a') {
if ((fd = trap(1, OPEN, name, 1)) < 0)
fd = trap(1, CREATE, name, 0);
else if (trap(1, LSEEK, 0L, fd, 2) < 0L)
fd = -1;
m = WR;
}
else { /* anything goes here, usually '+' */
fd = trap(1, OPEN, name, 3);
m = RDWR;
}
}
if (mode[1] == 'b')
m |= BINARY;
if (fd < 0) return NULL;
s->len = s->idx = 0;
s->fd = fd;
s->mode = m;
return s;
}
/* put a string onto the stream */
fputs(s, f) char *s; FILE *f; {
while (*s) putc(*s++, f);
}
/* get a string from stdin */
char *
gets(b) char *b; {
int c;
char *r;
r = b;
if ((c = getc(stdin)) == EOF)
return NULL;
while (c != '\n' && c != EOF) {
*b++ = c;
c = getc(stdin);
}
*b = 0;
return r;
}
/* get a character from standard input */
getchar() { return getc(stdin); }
/* get a character from a stream, map CR/NL to NL, handle console */
getc(s) FILE *s; {
int i, l, c, r, m;
if (s == NULL) return EOF;
m = (s->mode & RDWR);
if (m == RDWR) {
l = trap(1, READ, s->fd, (long) 1, s->buf);
if (l != 1) return EOF;
i = 0;
}
else if (m == RD) {
i = s->idx;
while (i >= s->len) {
l = trap(1, READ, s->fd, (long) MAXBUF, s->buf);
if (l <= 0) {
s->idx = s->len = 0;
return EOF;
}
s->len = l;
i = 0;
}
s->idx = i + 1;
}
else return EOF;
c = s->buf[i] & 255;
if (s->fd == 0) { /* tty input */
if (c == '\r')
trap(1, 2, (c = '\n'));
else if (c == 0x04) /* control D */
c = EOF;
}
if (c == '\r' && !(s->mode & BINARY))
c = getc(s);
return c;
}
/* output characters to a stream */
putchar(c) { putc(c, stdout); }
puts(s) char *s; {
while (*s) putc(*s++, stdout);
putc('\n', stdout);
}
putc(c, s) int c; FILE *s; {
int i, m, r = 0;
if (s == NULL) return EOF;
if (c == '\n' && !(s->mode & BINARY))
r = putc('\r', s);
r = 0;
m = s->mode & RDWR;
if (m == RDWR) {
s->buf[0] = c;
r = trap(1, WRITE, s->fd, (long) 1, s->buf);
}
else if (m == WR) {
if (s->idx == MAXBUF) r = fflush(s);
s->buf[s->idx] = c;
s->idx = s->idx + 1;
}
else return EOF;
return r <= 0 ? EOF : r;
}
/* flush out a buffer */
fflush(s) FILE *s; {
int r;
if (s->idx > 0)
r = trap(1, WRITE, s->fd, (long) s->idx, s->buf);
s->idx = 0;
return r <= 0 ? EOF : r;
}
/*
* TOS routines
*/
/* duplicate a file descriptor */
dup(fd) { return trap(1, 0x45, fd); }
dup2(fold, fnew) { return trap(1, 0x46, fold, fnew); }
/* get current directory: drive=0 -> current drive, drive=1 -> A:, etc */
getdir(buf, drive) char *buf; {
return trap(1, 0x47, buf, drive);
}
/*
* list the disk directory
* pat != NULL - set the DTA buffer, do an SFIRST
* pat == NULL - do a SNEXT
*/
listdir(pat, buf, mode) char *pat, *buf; {
if (pat) {
trap(1, 0x1A, buf);
return trap(1, 0x4E, pat, mode);
}
else return trap(1, 0x4F);
}
/* seek to a position in a file */
lseek(fd, offset, mode) int fd; long offset; int mode; {
return trap(1, 0x42, offset, fd, mode);
}
/* unlink a file */
unlink(name) char *name; { return trap(1, 0x41, name); }
/* close a file */
close(fd) { trap(1, 0x3E, fd); }
/* create a file */
creat(f, m) char *f; {
return trap(1, 0x3C, f, m);
}
/* open a file */
open(f, m) char *f; {
return trap(1, 0x3D, f, m);
}
/* read a file */
read(fd, buf, sz) int fd, sz; char *buf; {
return trap(1, 0x3F, fd, (long) sz, buf);
}
/* unix-like write system call */
write(fd, buf, sz) int fd, sz; char *buf; {
return trap(1, 0x40, fd, (long) sz, buf);
}
/*
* chmod(name, mode)
* mode = 0x00 - normal file (read/write)
* 0x01 - read only file
* 0x02 - hidden file
* 0x04 - system file
* 0x08 - file is volume label
* 0x10 - file is a subdirectory
* 0x20 - file is written and closed correctly
*/
chmod(name, mode) char *name; int mode; {
return trap(1, 0x43, name, mode, 0);
}
/* malloc, free, realloc: dynamic memory allocation */
#define MAXHUNK 20000
struct header {
struct header *next;
long size;
};
char *
realloc(r, n) struct header *r; unsigned n; {
struct header *p, *q;
char *malloc();
long *src, *dst;
long sz;
p = r - 1;
sz = (n + sizeof(struct header) + 7) & ~7;
if (p->size > sz) { /* block too big, split in two */
q = ((long) p) + sz;
q->size = p->size - sz;
free(q + 1);
p->size = sz;
}
else if (p->size < sz) { /* block too small, get new one */
dst = q = malloc(n);
if (q != NULL) {
src = r;
n = p->size - sizeof(struct header);
while (n > 0) {
*dst++ = *src++;
n -= sizeof(long);
}
}
free(r);
r = q;
}
/* else current block will do just fine */
return r;
}
char *
calloc(n, sz) unsigned n, sz; {
char *r, *s, *malloc();
unsigned total;
total = n * sz;
if ((r = s = malloc(total)) != NULL) {
while (total--)
*s++ = 0;
}
return r;
}
char *
malloc(n) unsigned n; {
extern struct header _base;
struct header *p, *q;
long sz, asz;
/* add a header to required size and round up */
sz = (n + sizeof(struct header) + 7) & ~7;
/* look for first block big enough in free list */
p = &_base;
q = _base.next;
while (q != NULL && q->size < sz) {
p = q;
q = q->next;
}
/* if not enough memory, get more from the system */
if (q == NULL) {
asz = (sz < MAXHUNK) ? MAXHUNK : sz;
q = trap(1, 0x48, asz);
if (((long)q) < 0L) /* no more memory */
return NULL;
p->next = q;
q->size = asz;
q->next = NULL;
}
if (q->size > sz + sizeof(struct header)) { /* chop it up */
q->size -= sz;
q = ((long) q) + q->size;
q->size = sz;
}
else { /* unlink from free list */
p->next = q->next;
}
/* skip over header, hope they don't touch it */
return ++q;
}
free(r) struct header *r; {
extern struct header _base;
struct header *p, *q, *t;
/* move back to uncover the header */
r--;
/* find where to insert it */
p = &_base;
q = _base.next;
while (q != NULL && q < r) {
p = q;
q = q->next;
}
/* merge after if possible */
t = ((long) r) + r->size;
if (q != NULL && t >= q) {
r->size += q->size;
q = q->next;
}
r->next = q;
/* merge before if possible, otherwise link it in */
t = ((long) p) + p->size;
if (t >= r) {
p->size += r->size;
p->next = r->next;
}
else p->next = r;
}
struct header _base = { NULL, 0L };
/* a UNIX style time command */
extern int _ma[];
long
time(tloc) long *tloc; {
int n, hms, y, m, d;
long t;
n = getdate();
y = (n >> 9) & 127; m = (n >> 5) & 15; d = n & 31;
hms = gettime();
t = (1460 * y) / 4 + ((y % 4) ? 1 : 0) + _ma[m] + d;
t = 2L * (long)(hms & 31)
+ 60L * (long)((hms >> 5) & 63)
+ 3600L * (24L * t + (long)((hms >> 11) & 31));
if (tloc != NULL) *tloc = t;
return t;
}
getdate() { return trap(1, 0x2A); }
gettime() { return trap(1, 0x2C); }
int _ma[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
/* setjmp/longjmp thanks to Bruce Szablak, use setjmp.h! */
setjmp(buf) char **buf; {
asm( lll 8 0);
asm( tda 0 0); /* a0 has pointer to buffer */
asm( tad 6 0); /* d0 has current link pointer */
asm( sol 0 0 0); /* save clp */
asm( lol 6 0 0); /* d0 has old link pointer */
asm( sol 0 4 0); /* save olp */
asm( lol 6 4 0); /* d0 has return address */
asm( sol 0 8 0); /* save ret */
return 0;
}
longjmp(buf, rc) char **buf; {
asm( lll 8 0);
asm( tda 0 0); /* buf in a0 */
asm( llw 12 0); /* rc in d0 */
asm( lol 0 0 1); /* current link pointer */
asm( tda 1 6); /* now in a6 */
asm( lol 0 4 1); /* old link pointer */
asm( sll 1 0); /* now on stack */
asm( lol 0 8 1); /* return address */
asm( sll 1 4); /* now on stack */
return; /* longjmp! */
}